#include "biz.h"
extern "C"
{
#include "sandbox/runner.h"
}

void biz::run()
{
    auto logger = core_data.logger.setBasicLogger("biz_run");
    json res;
    try
    {
        auto userData = json::parse(data);
        if(userData.find("forward_id") == userData.end() || !userData["forward_id"].is_string()) 
            //缺少forward_id或者forward_id不正确，不做处理
            return;
        if(userData.find("user_id") == userData.end() || userData.find("user_code") == userData.end()){
            //返回错误信息：用户数据不完整
            res["status"] = 400;
            res["msg"] = "用户信息不完整";
            res["forward_id"] = userData["forward_id"];
            string data = res.dump();
            echo(data, connection, core_data);
            //std::cout<<"用户信息不完整" << std::endl;
            std::cout<< data << std::endl;
            return; 
        }
        if(!userData["user_id"].is_number_integer() || !userData["user_code"].is_string()){
            //返回错误信息：不正确的用户数据
            res["status"] = 401;
            res["msg"] = "用户信息不正确";
            res["forward_id"] = userData["forward_id"];
            string data = res.dump();
            echo(data, connection, core_data); 
            return;
        }
        //这里后续考虑负载均衡的实现
        if(core_data.workers.numOfWaitingTasks() == max_waiting_tasks) //等待的用户脚本执行任务过多
        {
            //返回繁忙信息
            res["status"] = 402;
            res["msg"] = "当前服务器繁忙";
            res["forward_id"] = userData["forward_id"];
            string data = res.dump();
            return;
        }
        core_data.workers.enqueue(&biz::scriptExecution, this, userData);
    }
    catch(nlohmann::detail::parse_error){
        //json解析错误，向用户返回错误信息
        logger->error("错误的json格式");
        return;
    }

}

//执行用户脚本
void biz::scriptExecution(json userData)
{
    auto logger = core_data.logger.setBasicLogger("biz_scriptExecution");
    int ret;
    int user_id = userData["user_id"].get<int>();
    string forward_id = userData["forward_id"].get<string>();
    string user_code = userData["user_code"].get<string>();
    //std::cout << "开始执行user_id为" << user_id <<"用户的脚本" << std::endl; 
    string temp_path = script_root_path + std::to_string(user_id) + ".py";
    string output_path = script_output_root_path + std::to_string(user_id) + ".out";
    //std::cout << "用户脚本路径为" << temp_path.c_str() << std::endl;
    if((ret = open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR, 0777)) < 0) //创建用户脚本临时文件
    {
        //perror("打开文件失败");
        logger->error("打开临时文件失败：{}", MyLogger::getSysError().c_str());
        //向用户发送失败消息
        return;
    }
    if(write(ret,(const void*)user_code.c_str(), user_code.size()) < 0){
        //perror("写入文件失败");
        logger->error("写入临时文件失败：{}", MyLogger::getSysError().c_str());
        return;
    }
    close(ret);
    //std::cout << "user_code is " << user_code.c_str() << std::endl;
    if(mkfifo(output_path.c_str(), 0777) != 0){
        logger->error("创建管道失败：{}", MyLogger::getSysError().c_str());
        return;
    }
    config conf = {
        1000,              //max cpu time
        1000*2,           //max real time
        128*1024*1024,      //max memory
        32*1024*1024,       //max stack
        20,                //max process number
        10000,              //max output size
        0,                  //mem limit check only
        "/usr/bin/python3", //exec path
        NULL,               //input path
        const_cast<char*>(output_path.c_str()),               //output path
        "log.out",               //error path
        {"python3",const_cast<char*>(temp_path.c_str())}, //args
        NULL,               //env
        "log.out",          //log path
        "general",          //seccomp rule name
        0,                  //uid
        0                   //gid
    };
    std::thread _inspector(&biz::inspector,this, output_path.c_str(), userData);
    _inspector.detach();
    result res;
    ::run(&conf, &res);
    //std::cout << "running time is "<< res.cpu_time << std::endl;
    json val;
    json running_res;
    running_res["user_id"] = userData["user_id"];
    running_res["cpu_time"] = res.cpu_time;
    running_res["real_time"] = res.real_time;
    running_res["memory"] = res.memory;
    val["msg"] = running_res;
    val["status"] = 200;
    val["forward_id"] = userData["forward_id"];
    string tempData = val.dump();
    string data = X7::encoder(tempData);
    if(echo(data, connection, core_data) == -1){
        logger->warn("发送错误，错误原因: {}", MyLogger::getSysError().c_str());
    }
    if(remove(output_path.c_str()) < 0){
        perror("删除管道文件失败");
    }
    if(remove(temp_path.c_str())){
        perror("删除临时脚本失败");
    }
}

void biz::inspector(const char* FIFO, json userData)
{
    const int BUFFER_SIZE = 2048;
    int open_mode = O_RDONLY;
    char buffer[BUFFER_SIZE + 1];
    int res;
    memset(buffer, '\0', sizeof(buffer));
    int pipe_fd = open(FIFO, open_mode);
    if(pipe_fd != -1)
    {
        int i = 0;
        while((res = read(pipe_fd, buffer, BUFFER_SIZE)) > 0){
            string tempData(buffer, res);
            json msg;
            msg["status"] = 200;
            msg["msg"] = tempData;
            msg["forward_id"] = userData["forward_id"];
            string _data = msg.dump();
            string data = X7::encoder(_data);
            std::cout<<"用户数据是："<<tempData<<std::endl;
            echo(data, connection, core_data);
        }
        close(pipe_fd);
    }
}


